package com.tianji.learning.task;

import com.tianji.common.utils.CollUtils;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.po.PointsBoardSeason;
import com.tianji.learning.service.IPointsBoardSeasonService;
import com.tianji.learning.service.IPointsBoardService;
import com.tianji.learning.utils.TableInfoContext;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

import static com.tianji.learning.constants.LearningConstants.POINTS_BOARD_TABLE_PREFIX;

@Slf4j
@Component
@RequiredArgsConstructor
public class PointsBoardPersistentHandler {

    private final IPointsBoardSeasonService pointsBoardSeasonService;

    private final IPointsBoardService pointsBoardService;

    private final StringRedisTemplate redisTemplate;

    /**
     * 创建上赛季榜单表
     */
    // @Scheduled(cron = "0 0 3 1 * ?") // 每个月凌晨一号3点运行（单机版）
    @XxlJob("createTableJob")
    public void createPointsBoardTableOfLastSeason() {
        log.debug("创建上个赛季榜单表执行......");

        // 1. 获取上个月当前时间点
        LocalDate time = LocalDate.now().minusMonths(1);

        // 2. 查询上个赛季id
        PointsBoardSeason one = pointsBoardSeasonService.lambdaQuery()
                .le(PointsBoardSeason::getBeginTime, time)
                .ge(PointsBoardSeason::getEndTime, time)
                .one();

        log.debug("上赛季信息 {}", one);
        if (one == null) {
            return;
        }

        // 3. 创建上赛季榜单表
        pointsBoardSeasonService.createPointsBoardLastTable(one.getId());
    }

    /**
     * 持久化上赛季榜单数据
     */
    @XxlJob("savePointsBoard2DB")
    public void savePointsBoard2DB() {
        // 1. 获取上个月当前时间
        LocalDate time = LocalDate.now().minusMonths(1);

        // 2. 插叙赛季表, 获取上赛季信息
        PointsBoardSeason one = pointsBoardSeasonService.lambdaQuery()
                .le(PointsBoardSeason::getBeginTime, time)
                .ge(PointsBoardSeason::getEndTime, time)
                .one();

        log.debug("上赛季信息 {}", one);
        if (one == null) {
            return;
        }

        // 4. 计算动态表名, 存入 threadlocal
        String tableName = POINTS_BOARD_TABLE_PREFIX + one.getId();
        log.debug("动态表名为: {}", tableName);
        TableInfoContext.setInfo(tableName);

        // 3. 分页查 redis 中上赛季积分排行榜数据
        String format = time.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + format;

        int shardIndex = XxlJobHelper.getShardIndex(); // 当前分片的索引
        int shardTotal = XxlJobHelper.getShardTotal(); // 总的分片(实例)数

        int pageNO = shardIndex + 1;
        int pageSize = 5;
        while (true) {
            List<PointsBoard> list = pointsBoardService.queryCurrentBoard(key, pageNO, pageSize);
            if (CollUtils.isEmpty(list)) {
                break;
            }
            pageNO += shardTotal;

            // 5. 持久化
            for (PointsBoard board : list) {
                board.setId(Long.valueOf( board.getRank())); // 历史赛季排行表中 id 代表排名
                board.setRank(null);
            }
            pointsBoardService.saveBatch(list);
        }

        // 6. 清空 threadlocal 数据
        TableInfoContext.remove();
    }

    /**
     * 清除 redis 缓存
     */
    @XxlJob("clearPointsBoardFromRedis")
    public void clearPointsBoardFromRedis(){
        // 1.获取上月时间
        LocalDateTime time = LocalDateTime.now().minusMonths(1);

        // 2.计算key
        String format = time.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + format;

        // 3.删除
        redisTemplate.unlink(key);
    }
}
